import {
  BaseCommand,
  CENTEREVENTS,
  EventsRes,
  KEYBOARD_KEY,
  MouseInfo,
} from '@amcax/base';
import { csEvent } from '@app-base/common/events/EventCenter';
import { ctx2 } from '@app-base/module';

class MouseAreaResizer {
  startPosition: MouseInfo;
  endPosition: MouseInfo;

  domStartPosition: MouseInfo;
  domEndPosition: MouseInfo;

  element: HTMLDivElement;
  isActive = false;

  onPointerDown = (e: EventsRes<PointerEvent>) => {
    this.startPosition = e.mouse;
    this.domStartPosition = { x: e.event.clientX, y: e.event.clientY };
  };

  onPointerMove = (e: EventsRes<PointerEvent>) => {
    if (this.domStartPosition == null) {
      return;
    }
    this.endPosition = e.mouse;
    this.domEndPosition = { x: e.event.clientX, y: e.event.clientY };
    this.updateElement();
  };

  updateElement = () => {
    if (this.element == null) {
      this.element = document.createElement('div');
      document.body.appendChild(this.element);
      this.element.style.border = '2px solid #55aaff';
      this.element.style.backgroundColor = 'rgba(75, 160, 255, 0.1)';
      this.element.style.position = 'fixed';
      this.element.style.pointerEvents = 'none';
      this.element.style.zIndex = '999';
    }

    const left = Math.min(this.domStartPosition.x, this.domEndPosition.x);
    this.element.style.left = `${left}px`;
    this.element.style.width = `${Math.max(this.domStartPosition.x, this.domEndPosition.x) - left}px`;

    const top = Math.min(this.domStartPosition.y, this.domEndPosition.y);
    this.element.style.top = `${top}px`;
    this.element.style.height = `${Math.max(this.domStartPosition.y, this.domEndPosition.y) - top}px`;
  };

  onKeyUp = (e: EventsRes<KeyboardEvent>) => {
    if (e.key === KEYBOARD_KEY.ESC) {
      this.end();
    }
  };

  onCommandFinish: VoidFunction;

  start = (onFinished: VoidFunction) => {
    if (this.isActive) {
      this.end();
      return;
    }
    this.isActive = true;
    this.onCommandFinish = onFinished;
    csEvent().on(CENTEREVENTS.POINTERDOWN, this.onPointerDown);
    csEvent().on(CENTEREVENTS.POINTERMOVE, this.onPointerMove);
    csEvent().on(CENTEREVENTS.POINTERUP, this.end);
    csEvent().on(CENTEREVENTS.KEYUP, this.onKeyUp);
  };

  end = () => {
    if (
      this.startPosition != null &&
      this.endPosition != null &&
      this.element != null
    ) {
      const sceneSetup = ctx2.viewer.sceneSetup;
      sceneSetup.translateToCenterAndSize(
        [
          (this.startPosition.x + this.endPosition.x) / 2,
          (this.startPosition.y + this.endPosition.y) / 2,
        ],
        {
          x: Math.abs(this.startPosition.x - this.endPosition.x),
          y: Math.abs(this.startPosition.y - this.endPosition.y),
        },
      );
    }

    csEvent().off(CENTEREVENTS.POINTERDOWN, this.onPointerDown);
    csEvent().off(CENTEREVENTS.POINTERMOVE, this.onPointerMove);
    csEvent().off(CENTEREVENTS.POINTERUP, this.end);
    csEvent().off(CENTEREVENTS.KEYUP, this.onKeyUp);
    this.startPosition = null;
    this.endPosition = null;
    this.domStartPosition = null;
    this.domEndPosition = null;
    if (this.element != null) {
      document.body.removeChild(this.element);
      this.element = null;
    }
    this.onCommandFinish?.();

    this.onCommandFinish = null;
    this.isActive = false;
  };
}

const mouseAreaResizer = new MouseAreaResizer();

export const cmdResizeToArea: BaseCommand = {
  id: 'CmdResizeToArea',
  label: 'command.resize-to-area',
  icon: 'commands/common/focus-area',
  invoke: mouseAreaResizer.start,
  standalone: true,
};
